﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SocketTools;

namespace CameraViewer.NetWorking
{
    class Controller : IDisposable
    {
        private readonly string _peerIp;
        private readonly int _port;
        private SocketWrench _socketWrench;
        private bool _isDisposed;

        private const int Control = 5000;
        private const int Status = 5001;

        public Controller(string peerIp, int port)
        {
            _peerIp = peerIp;
            _port = port;
        }

        public void ConnectAsync()
        {
            _socketWrench = new SocketWrench();
            _socketWrench.Blocking = true;
            if (!_socketWrench.Initialize("FMINREIKFOJBMIGJECOLFTHMCPCRUK"))
            {
                throw new InvalidOperationException("socket tools not licensed");
            }

            if (!_socketWrench.Connect(_peerIp, _port))
            {
                throw new Exception("connection failed");
            }

        }

        public void StartAutoCapture(bool enable)
        {
            var b = (byte)(enable ? 0x01 : 0x00);
            SendCommandAsync(Control, new byte[] { b });
            var s = QueryAutoCapture();
            if (s != enable)
            {
                throw new Exception("state switch failed");
            }
        }

        public bool QueryAutoCapture()
        {
            SendCommandAsync(Status, new byte[0]);
            var p = ReadPacket();
            if (p.MessageId == Status && p.Payload.Length == 1)
            {
                return p.Payload[0] == 1;
            }

            throw new Exception("invalid response from peer");
        }


        private void SendCommandAsync(short command, byte[] payload)
        {
            var data = new TlvLib.RawPacket() { MessageId = command, Payload = payload };
            var buffer = new TlvLib.TlvPacker().Pack(data);
            SendBufferAsync(buffer);
        }

        private void SendBufferAsync(byte[] buffer)
        {

            var res = _socketWrench.Write(buffer);
            if (res == -1)
            {
                throw new Exception("socket write error: " + _socketWrench.LastErrorString);
            }

        }

        private TlvLib.RawPacket ReadPacket()
        {
            var header = new byte[4 + 4];
            _socketWrench.Read(header);
            var len = System.Net.IPAddress.NetworkToHostOrder(BitConverter.ToInt32(header, 4));
            var v = new byte[len];
            _socketWrench.Read(v);

            var t = System.Net.IPAddress.NetworkToHostOrder(BitConverter.ToInt16(header, 2));
            var p = new TlvLib.RawPacket() { IsRequest = false, MessageId = t, Payload = v };
            return p;
        }

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (_isDisposed)
            {
                return;
            }

            if (disposing)
            {
                if (_socketWrench != null)
                {
                    _socketWrench.Dispose();
                }
            }

            _socketWrench = null;

            _isDisposed = true;
        }

        ~Controller()
        {
            Dispose(false);
        }
    }
}
